/************************************************************************

								Heroes IV
					  Copyright 2001, The 3DO Company

	------------------------------------------------------------------
  						  dialog_caravan_arrivals.cpp

	$Header: $

	$NoKeywords: $

 ************************************************************************/
// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "dialog_caravan_arrivals.h"

#include "adaptor_handler.h"
#include "adventure_map.h"
#include "bitmap_group.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_window.h"
#include "bound_handler.h"
#include "button.h"
#include "button_cache.h"
#include "caravan.h"
#include "caravan_set.h"
#include "creature_array_window.h"
#include "foreign_creature_array_window_controls.h"
#include "format_string.h"
#include "external_string.h"
#include "interface_help.h"
#include "keyword_replacer.h"
#include "minimum_maximum.h"
#include "player.h"
#include "replace_keywords.h"
#include "scrollbar.h"
#include "simple_dialog.h"
#include "standard_fonts.h"
#include "text_window.h"
#include "town.h"

extern t_button_cache g_ok_button;
t_button_cache const  k_move_caravan_to_garrison_button( "button.move_caravan_to_garrison" );
t_button_cache const  k_move_caravan_to_visiting_button( "button.move_caravan_to_visiting" );
extern t_button_cache const k_move_garrison_down_button;
extern t_button_cache const k_move_up_button;

namespace
{
	t_external_string const k_title( "caravan_arrivals.title" );
	t_external_string const k_text( "caravan_arrivals.text" );
	t_external_string const k_no_arrivals( "caravan_arrivals.no_arrivals" );

	t_bitmap_group_cache const k_bitmaps( "dialog.caravan_arrival" );
};

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
t_dialog_caravan_arrivals::t_dialog_caravan_arrivals( t_window * parent, t_adventure_map & map )
	: t_window( k_completely_transparent, parent ),
	  m_map( map )
{
}

// ---------------------------------------------------------------------------
// Initialize dialog. Continue only if the return value is true
// ---------------------------------------------------------------------------
bool t_dialog_caravan_arrivals::init_dialog( t_town & town, t_creature_array * visiting_army )
{
	t_player & player = m_map.get_player();
	int        player_number = m_map.get_player_number();
	bool       foreigners = (    town.get_owner_number() != player_number 
							  || ( visiting_army && visiting_army->get_owner_number() != player_number ) );
	
	t_keyword_replacer town_replacer;
	town_replacer.add_keyword( "%town", town.get_name() );

	t_caravan_set const & caravans = player.get_caravans();
	t_caravan_set::const_iterator it;

	for ( it = caravans.get_lower_bound_of_destination( &town ); it != caravans.end() && (*it)->get_destination().get() == &town; it++ )
	{
		if ( (*it)->has_arrived() )
			m_caravans.push_back( *it );
	}
	
	if ( m_caravans.empty() )
	{
		ok_dialog( town_replacer( k_no_arrivals ), true );
		return false;
	}


	// Create subwindows
	m_bitmaps = k_bitmaps.get();
	t_help_block const& help = get_help_block( "caravan_arrival" );
	t_help_block const& shared_help = get_help_block( "shared" );

	t_bitmap_layer const * layer;
	t_window *             background;
	t_text_window *		   text_window;
	t_button *             button;

	layer = m_bitmaps->find( "background" );
	background = new t_bitmap_layer_window( layer, t_screen_point(0, 0), this );

	layer = m_bitmaps->find( "text scroll" );
	new t_bitmap_layer_window( layer, t_screen_point(0, 0), background );

	layer = m_bitmaps->find( "title scroll" );
	new t_bitmap_layer_window( layer, t_screen_point(0, 0), background );

	layer = m_bitmaps->find( "title" );
	text_window = new t_text_window( get_font( 20 ), layer->get_rect(), background, town_replacer( k_title ), t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( false );
	text_window->set_justification( k_justify_center );

	layer = m_bitmaps->find( "text" );
	text_window = new t_text_window( get_font( 16 ), layer->get_rect(), background, town_replacer( k_text ), t_pixel_24(0,0,0) );
	text_window->set_drop_shadow( false );
	text_window->set_justification( k_justify_center );

	layer = m_bitmaps->find( "ok_button" );
	button = new t_button( g_ok_button.get(), layer->get_rect().top_left(), background );
	button->set_click_handler( bound_handler( *this, &t_dialog_caravan_arrivals::ok_clicked ) );
  set_help( button, shared_help, "ok" );

	// Create creature windows
	t_creature_array_window::t_layout garrison_layout;
	t_bitmap_layer const * background_layer;
	if ( visiting_army )
	{
		background_layer = m_bitmaps->find( "double_garrison_background" );
		layer = m_bitmaps->find( "double_garrison_rings" );
		garrison_layout = t_creature_array_window::k_top_row;
	}
	else
	{
		background_layer = m_bitmaps->find( "single_garrison_background" );
		layer = m_bitmaps->find( "single_garrison_rings" );
		garrison_layout = t_creature_array_window::k_single_row;
	}

	new t_bitmap_layer_window( background_layer, t_screen_point(0, 0), background );

	m_garrison_window = new t_creature_array_window( layer->get_rect().top_left(), &town, garrison_layout, 0, background );
	
	if ( foreigners )
		setup_foreign_creature_array_window_controls( m_map, m_garrison_window );

	if ( visiting_army )
	{
		t_screen_point visiting_point = layer->get_rect().top_left();
		visiting_point.y += m_garrison_window->get_frame_height();

		m_visiting_window = new t_creature_array_window( visiting_point, visiting_army, t_creature_array_window::k_bottom_row, 0, background );
		m_visiting_window->link_selection( m_garrison_window );
		m_visiting_window->move_before( m_garrison_window );

		layer = m_bitmaps->find( "move_garrison_button" );
		button = new t_button( k_move_garrison_down_button.get(), layer->get_rect().top_left(), background );
		if ( town.get_owner_number() == player_number )
		{
			button->set_click_handler( discard_argument< t_button * >( bound_handler( *this, &t_dialog_caravan_arrivals::move_garrison_clicked ) ) );
		}
		else
		{
			button->enable( false );
		}
   		set_help( button, shared_help, "move_garrison_to_adjacent" );

		layer = m_bitmaps->find( "move_visiting_button" );
		button = new t_button( k_move_up_button.get(), layer->get_rect().top_left(), background );
		if ( visiting_army->get_owner_number() == player_number )
		{
			button->set_click_handler( discard_argument< t_button * >( bound_handler( *this, &t_dialog_caravan_arrivals::move_visiting_clicked ) ) );
		}
		else
		{
			button->enable( false );
		}
   		set_help( button, shared_help, "move_adjacent_to_garrison" );

		if ( foreigners )
			setup_foreign_creature_array_window_controls( m_map, m_visiting_window );
	}

	// Create scrollbar
	if ( m_caravans.size() > k_displayed_caravans )
	{
		layer = m_bitmaps->find( "scrollbar" );
		t_scrollbar * scrollbar = new t_scrollbar( layer->get_rect().top_left(), layer->get_height(), background, 
												   0, m_caravans.size() - k_displayed_caravans );
		scrollbar->set_page_size( k_displayed_caravans);
		scrollbar->set_handler( bound_handler( *this, &t_dialog_caravan_arrivals::scroll ) );
	}

	// Create caravan window(s)
	int visible_caravans = minimum( unsigned int( k_displayed_caravans ), m_caravans.size() );
	int	i;

	layer = m_bitmaps->find( "caravan_1" );
	t_screen_point caravan_1_point = layer->get_rect().top_left();

	background_layer = m_bitmaps->find( "caravan_background" );

	layer = m_bitmaps->find( "move_caravan_to_garrison_button" );
	t_screen_point move_to_garrison_offset = layer->get_rect().top_left() - caravan_1_point;
	
	layer = m_bitmaps->find( "move_caravan_to_visiting_button" );
	t_screen_point move_to_visiting_offset = layer->get_rect().top_left() - caravan_1_point;
	
	layer = m_bitmaps->find( "caravan_rings" );
	t_screen_point caravan_rings_offset = layer->get_rect().top_left() - caravan_1_point;

	for ( i = 0; i < visible_caravans; i++ )
	{
		t_screen_point caravan_point;
		if ( i == 0 )
		{
			caravan_point = caravan_1_point;
		}
		else
		{
			layer = m_bitmaps->find( format_string("caravan_%d", i + 1 ) );
			caravan_point = layer->get_rect().top_left();
		}

		// Background
		t_screen_point diff = caravan_point - caravan_1_point;
		new t_bitmap_layer_window( background_layer, diff, background );

		// Buttons
		button = new t_button( k_move_caravan_to_garrison_button.get(), caravan_point + move_to_garrison_offset, background );
		button->set_click_handler( discard_argument< t_button * >( add_argument( bound_handler( *this, &t_dialog_caravan_arrivals::move_to_garrison_clicked ), i ) ) );
	  	set_help( button, help, "move_caravan_to_garrison" );

		if ( visiting_army )
		{
			button = new t_button( k_move_caravan_to_visiting_button.get(), caravan_point + move_to_visiting_offset, background );
			button->set_click_handler( discard_argument< t_button * >( add_argument( bound_handler( *this, &t_dialog_caravan_arrivals::move_to_visiting_clicked ), i ) ) );
		  	set_help( button, help, "move_caravan_to_visiting" );
		}

		m_visible_caravans[i] = new t_creature_array_window( caravan_point + caravan_rings_offset, 
															 m_caravans[i].get(),
															 t_creature_array_window::k_single_row,
															 0,
															 background );

		m_visible_caravans[i]->link_selection( m_garrison_window );

		if ( foreigners )
			setup_foreign_creature_array_window_controls( m_map, m_visible_caravans[i] );
	}
	
	t_screen_rect rect = m_bitmaps->get_rect();
	rect += (get_parent()->get_client_rect().size() - rect.size()) / 2;
	init( rect );

	return true;
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void t_dialog_caravan_arrivals::move_garrison_clicked()
{
	assert( m_visiting_window.get() != NULL );

	if ( m_visiting_window.get() != NULL )
		m_visiting_window->merge( m_garrison_window );
}


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void t_dialog_caravan_arrivals::move_to_garrison_clicked( int visible_index )
{
	m_garrison_window->merge( m_visible_caravans[visible_index] );
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void t_dialog_caravan_arrivals::move_to_visiting_clicked( int visible_index )
{
	assert( m_visiting_window.get() != NULL );

	if ( m_visiting_window.get() != NULL )
		m_visiting_window->merge( m_visible_caravans[visible_index] );
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void t_dialog_caravan_arrivals::move_visiting_clicked()
{
	assert( m_visiting_window.get() != NULL );

	if ( m_visiting_window.get() != NULL )
		m_garrison_window->merge( m_visiting_window );
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void t_dialog_caravan_arrivals::ok_clicked( t_button * )
{
	// Erase any emptied caravans
	int i;
	for ( i = 0; i < m_caravans.size(); i++ )
	{
		t_caravan_ptr & caravan = m_caravans[i];

		if ( caravan->empty() )
		{
			caravan->get_owner()->remove( caravan );
			m_map.remove_caravan( caravan );
		}
	}

	close();
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
void t_dialog_caravan_arrivals::scroll( t_scrollbar *, int position )
{
	int i;
	for ( i = 0; i < k_displayed_caravans; i++ )
	{
		if ( m_visible_caravans[i].get() != NULL )
		{
			assert( position + i < m_caravans.size() );

			if ( position + i < m_caravans.size() )
			{
				m_visible_caravans[i]->set_army( m_caravans[ i + position ] );
			}
			else
			{
				m_visible_caravans[i]->set_army( NULL );
			}

			m_visible_caravans[i]->select_creature( -1 );
		}
	}
}
